Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support


Apple IIGS
#38:    List Controls in Dialog Boxes

Revised by:    Keith Rollin                                     November 1988
Written by:    Keith Rollin                                          May 1988

This Technical Note describes how to include a list control into a dialog box.  
Sample APW C source code is included.
_____________________________________________________________________________

The need to put a list control into a dialog box is obvious.  The Print 
Manager does it.  The Font Manager does it.  You may want to use one in your 
own application to manage a list of data-base fields or spreadsheet functions, 
however, performing the task is not as obvious as the need.  This Note 
describes the procedure and contains a sample C fragment for illustration.


Individual Steps

Basically, there are three check-off items for putting a list control into a 
dialog box:

1.    You must install the list explicitly into the dialog box yourself.  
      This should be done after you have created the dialog box with a 
      call to NewModalDialog or GetNewModalDialog.  Do not install it as 
      a UserItem or UserCtlItem.  Installing it as a UserItem would 
      cause the Dialog Manager to place an invisible custom control over 
      the list, preventing later use of FindControl to manage it.  
      Installing the list as a UserCtlItem does not allow the list 
      control to be properly initialized.

        InitValues()
        {
            /* Get a Full Screen, invisible dialog window with only
                  a Quit button in it*/
            myDialog = GetNewModalDialog(&PrintDialog);
    
            /* Add this List Control ourselves */
            myListHndl = CreateList(myDialog,&myList);
    
            /* Get the handle for the Scrollbar Control */
            listScrollHandle = (**myListHndl).ctlListBar;
    
            /* Save and Zero out the RefCons */
            listRefCons = GetCtlRefCon(myListHndl);
            scrollRefCons = GetCtlRefCon(listScrollHandle);
            ZeroRefCons(); /* This is explained below in item #3 */
    
            /* Now show the dialog box */
            ShowWindow(myDialog);
        }

2.    Because the list control is not a dialog item, a custom FilterProc 
      must be installed for ModalDialog to test for hits.  Pass the 
      address of this routine (with the high bit set so that default 
      handling of items will be in effect) when you call ModalDialog.

        pascal Word myFilterProc(theDialog, theEvent, theItem)
            GrafPortPtr    theDialog;
            EventRecord    *theEvent;
            long           *theItem;
    
        {
            CtlRecHndl  tHandle;
      
            if ((*theEvent).what == mouseDownEvt) {
                FindControl(&tHandle,(*theEvent).where,theDialog);
                if ((tHandle == myListHndl) || (tHandle == listScrollHandle)) {
    
                    /* Set the RefCons back to the way the list
                       manager likes them */
                    RestoreRefCons();
                    TrackControl((*theEvent).where,(LongProcPtr) -1, tHandle);
                    ZeroRefCons();
    
                    /* Tell the Dialog Manager that we handled this event */
                    return(true);
                }
            }
            /* We didn't do anything, so return false to get Dialog Manager
                to handle this event */
          return(false);
        }

3.    The Dialog Manager uses the RefCon field of its items (all of 
      which are installed as controls).  Unfortunately, the List Manager 
      also uses the RefCon field for its own purposes.  This shared use 
      means that a judicious juggling of those values is required.  This 
      juggling is the reason for the two routines RestoreRefCons and 
      ZeroRefCons used above.

        /* Zero out the RefCons for the Dialog Manager */
        ZeroRefCons()
        {
            SetCtlRefCon(0,myListHndl);
            SetCtlRefCon(0,listScrollHandle);
        }
    
        /* Restore the RefCons for the List Manager */
        RestoreRefCons()
        {
            SetCtlRefCon(listRefCons,myListHndl);
            SetCtlRefCon(scrollRefCons,listScrollHandle);
        }

Putting It All Together

Here are most of the pieces put together.  InitTools and ShutDownStuff 
routines have been omitted, but they are straightforward.

char               **y,*z;
GrafPortPtr        myDialog;
ListCtlRecHndl     myListHndl;
CtlRecHndl         listScrollHandle;
long               listRefCons, scrollRefCons;


#define Quit        ok

char    quitStr[]    = "\pQuit";

ItemTemplate quitButton =  {
             Quit,
             140,450,154,590,
             buttonItem,
             quitStr,
             0,
             0,
             NULL};


DialogTemplate PrintDialog = {
               30,20,190,620,
               false,
               0,
               &quitButton,
               NULL};


char string1[] = "String1";
char string2[] = "String2";
char string3[] = "String3";
char string4[] = "String4";
char string5[] = "String5";
char string6[] = "String6";
char string7[] = "String7";
char string8[] = "String8";

MemRec  myMembers[8] = {
            string1, 00,
            string2, 00,
            string3, 00,
            string4, 00,
            string5, 00,
            string6, 00,
            string7, 00,
            string8, 00};

ListRec  myList = {
            40,175,102,400,          /* Enclosing Rectangle */
            8,                       /* Number of List Members */
            6,                       /* Max Viewable members */
            3,                       /* Bit Flag */
            1,                       /* First member in view */
            NULL,                    /* List control's handle */
            NULL,                    /* Address of Custom drawing routine */
            10,                      /* Height of list members */
            5,                       /* Size of Member Records */
            (MemRecPtr)myMembers,    /* Pointer to first element in MemRec[] */
            NULL,                    /* Becomes Control's refCon */
            NULL                     /* Color table for list's scroll bar */
            };

/* ************************** */

main()
{
    word what;

    InitTools();                     /* initialize tools */
    InitValues();                    /* Get dialog box. Install List control */
    do {
            what = ModalDialog((WordProcPtr)((long)myFilterProc | 0x80000000)); 
    } while (what != Quit);
    ShutDownStuff();  
}

pascal Word myFilterProc(theDialog, theEvent, theItem)
    GrafPortPtr    theDialog;
    EventRecord    *theEvent;
    long           *theItem;

{
    CtlRecHndl    tHandle;

    if ((*theEvent).what == mouseDownEvt) {
        FindControl(&tHandle,(*theEvent).where,theDialog);
        if ((tHandle == myListHndl) || (tHandle == listScrollHandle)) {

            /* Set the RefCons back to the way the list manager likes them */
            RestoreRefCons();
            TrackControl((*theEvent).where,(LongProcPtr) -1, tHandle);
            ZeroRefCons();

            /* Tell the Dialog Manager that we handled this event */
            return(true);
        }
    }
    /* We didn't do anything, so return false to get Dialog Manager
        to handle this event */
  return(false);
}

/* Zero out the Refcons for the Dialog Manager */
ZeroRefCons()
{
    SetCtlRefCon(0,myListHndl);
    SetCtlRefCon(0,listScrollHandle);
}

/* Restore the Refcons for the List Manager */
RestoreRefCons()
{
    SetCtlRefCon(listRefCons,myListHndl);
    SetCtlRefCon(scrollRefCons,listScrollHandle);
}


InitValues()
{
    /* Get a Full Screen, invisible dialog window with
       only a Quit button in it*/
    myDialog = GetNewModalDialog(&PrintDialog);

    /* Add this List Control ourselves */
    myListHndl = CreateList(myDialog,&myList);

    /* Get the handle for the Scrollbar Control */
    listScrollHandle = (**myListHndl).ctlListBar;

    /* Save and Zero out the RefCons */
    listRefCons = GetCtlRefCon(myListHndl);
    scrollRefCons = GetCtlRefCon(listScrollHandle);
    ZeroRefCons();

    /* Now show the dialog box */
    ShowWindow(myDialog);
}


